@@ -11,6 +11,8 @@ module Agents |
||
| 11 | 11 |
|
| 12 | 12 |
The `type` can be one of #{VALID_COMPARISON_TYPES.map { |t| "`#{t}`" }.to_sentence} and compares with the `value`.
|
| 13 | 13 |
|
| 14 |
+ The `value` can be a single value or an array of values. In the case of an array, if one or more values match then the rule matches. |
|
| 15 |
+ |
|
| 14 | 16 |
All rules must match for the Agent to match. The resulting Event will have a payload message of `message`. You can include extractions in the message, for example: `I saw a bar of: <foo.bar>` |
| 15 | 17 |
|
| 16 | 18 |
Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent. |
@@ -49,25 +51,30 @@ module Agents |
||
| 49 | 51 |
incoming_events.each do |event| |
| 50 | 52 |
match = options['rules'].all? do |rule| |
| 51 | 53 |
value_at_path = Utils.value_at(event['payload'], rule['path']) |
| 52 |
- case rule['type'] |
|
| 54 |
+ rule_values = rule['value'] |
|
| 55 |
+ rule_values = [rule_values] unless rule_values.is_a?(Array) |
|
| 56 |
+ |
|
| 57 |
+ match_found = rule_values.any? do |rule_value| |
|
| 58 |
+ case rule['type'] |
|
| 53 | 59 |
when "regex" |
| 54 |
- value_at_path.to_s =~ Regexp.new(rule['value'], Regexp::IGNORECASE) |
|
| 60 |
+ value_at_path.to_s =~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
| 55 | 61 |
when "!regex" |
| 56 |
- value_at_path.to_s !~ Regexp.new(rule['value'], Regexp::IGNORECASE) |
|
| 62 |
+ value_at_path.to_s !~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
| 57 | 63 |
when "field>value" |
| 58 |
- value_at_path.to_f > rule['value'].to_f |
|
| 64 |
+ value_at_path.to_f > rule_value.to_f |
|
| 59 | 65 |
when "field>=value" |
| 60 |
- value_at_path.to_f >= rule['value'].to_f |
|
| 66 |
+ value_at_path.to_f >= rule_value.to_f |
|
| 61 | 67 |
when "field<value" |
| 62 |
- value_at_path.to_f < rule['value'].to_f |
|
| 68 |
+ value_at_path.to_f < rule_value.to_f |
|
| 63 | 69 |
when "field<=value" |
| 64 |
- value_at_path.to_f <= rule['value'].to_f |
|
| 70 |
+ value_at_path.to_f <= rule_value.to_f |
|
| 65 | 71 |
when "field==value" |
| 66 |
- value_at_path.to_s == rule['value'].to_s |
|
| 72 |
+ value_at_path.to_s == rule_value.to_s |
|
| 67 | 73 |
when "field!=value" |
| 68 |
- value_at_path.to_s != rule['value'].to_s |
|
| 74 |
+ value_at_path.to_s != rule_value.to_s |
|
| 69 | 75 |
else |
| 70 | 76 |
raise "Invalid type of #{rule['type']} in TriggerAgent##{id}"
|
| 77 |
+ end |
|
| 71 | 78 |
end |
| 72 | 79 |
end |
| 73 | 80 |
|
@@ -71,6 +71,28 @@ describe Agents::TriggerAgent do |
||
| 71 | 71 |
}.should change { Event.count }.by(1)
|
| 72 | 72 |
end |
| 73 | 73 |
|
| 74 |
+ it "handles array of regex" do |
|
| 75 |
+ @event.payload['foo']['bar']['baz'] = "a222b" |
|
| 76 |
+ @checker.options['rules'][0] = {
|
|
| 77 |
+ 'type' => "regex", |
|
| 78 |
+ 'value' => ["a\\db", "a\\Wb"], |
|
| 79 |
+ 'path' => "foo.bar.baz", |
|
| 80 |
+ } |
|
| 81 |
+ lambda {
|
|
| 82 |
+ @checker.receive([@event]) |
|
| 83 |
+ }.should_not change { Event.count }
|
|
| 84 |
+ |
|
| 85 |
+ @event.payload['foo']['bar']['baz'] = "a2b" |
|
| 86 |
+ lambda {
|
|
| 87 |
+ @checker.receive([@event]) |
|
| 88 |
+ }.should change { Event.count }.by(1)
|
|
| 89 |
+ |
|
| 90 |
+ @event.payload['foo']['bar']['baz'] = "a b" |
|
| 91 |
+ lambda {
|
|
| 92 |
+ @checker.receive([@event]) |
|
| 93 |
+ }.should change { Event.count }.by(1)
|
|
| 94 |
+ end |
|
| 95 |
+ |
|
| 74 | 96 |
it "handles negated regex" do |
| 75 | 97 |
@event.payload['foo']['bar']['baz'] = "a2b" |
| 76 | 98 |
@checker.options['rules'][0] = {
|
@@ -89,6 +111,24 @@ describe Agents::TriggerAgent do |
||
| 89 | 111 |
}.should change { Event.count }.by(1)
|
| 90 | 112 |
end |
| 91 | 113 |
|
| 114 |
+ it "handles array of negated regex" do |
|
| 115 |
+ @event.payload['foo']['bar']['baz'] = "a2b" |
|
| 116 |
+ @checker.options['rules'][0] = {
|
|
| 117 |
+ 'type' => "!regex", |
|
| 118 |
+ 'value' => ["a\\db", "a2b"], |
|
| 119 |
+ 'path' => "foo.bar.baz", |
|
| 120 |
+ } |
|
| 121 |
+ |
|
| 122 |
+ lambda {
|
|
| 123 |
+ @checker.receive([@event]) |
|
| 124 |
+ }.should_not change { Event.count }
|
|
| 125 |
+ |
|
| 126 |
+ @event.payload['foo']['bar']['baz'] = "a3b" |
|
| 127 |
+ lambda {
|
|
| 128 |
+ @checker.receive([@event]) |
|
| 129 |
+ }.should change { Event.count }.by(1)
|
|
| 130 |
+ end |
|
| 131 |
+ |
|
| 92 | 132 |
it "puts can extract values into the message based on paths" do |
| 93 | 133 |
@checker.receive([@event]) |
| 94 | 134 |
Event.last.payload['message'].should == "I saw 'a2b' from Joe" |
@@ -109,6 +149,21 @@ describe Agents::TriggerAgent do |
||
| 109 | 149 |
}.should_not change { Event.count }
|
| 110 | 150 |
end |
| 111 | 151 |
|
| 152 |
+ it "handles array of numerical comparisons" do |
|
| 153 |
+ @event.payload['foo']['bar']['baz'] = "5" |
|
| 154 |
+ @checker.options['rules'].first['value'] = [6, 3] |
|
| 155 |
+ @checker.options['rules'].first['type'] = "field<value" |
|
| 156 |
+ |
|
| 157 |
+ lambda {
|
|
| 158 |
+ @checker.receive([@event]) |
|
| 159 |
+ }.should change { Event.count }.by(1)
|
|
| 160 |
+ |
|
| 161 |
+ @checker.options['rules'].first['value'] = [4, 3] |
|
| 162 |
+ lambda {
|
|
| 163 |
+ @checker.receive([@event]) |
|
| 164 |
+ }.should_not change { Event.count }
|
|
| 165 |
+ end |
|
| 166 |
+ |
|
| 112 | 167 |
it "handles exact comparisons" do |
| 113 | 168 |
@event.payload['foo']['bar']['baz'] = "hello world" |
| 114 | 169 |
@checker.options['rules'].first['type'] = "field==value" |
@@ -124,6 +179,21 @@ describe Agents::TriggerAgent do |
||
| 124 | 179 |
}.should change { Event.count }.by(1)
|
| 125 | 180 |
end |
| 126 | 181 |
|
| 182 |
+ it "handles array of exact comparisons" do |
|
| 183 |
+ @event.payload['foo']['bar']['baz'] = "hello world" |
|
| 184 |
+ @checker.options['rules'].first['type'] = "field==value" |
|
| 185 |
+ |
|
| 186 |
+ @checker.options['rules'].first['value'] = ["hello there", "hello universe"] |
|
| 187 |
+ lambda {
|
|
| 188 |
+ @checker.receive([@event]) |
|
| 189 |
+ }.should_not change { Event.count }
|
|
| 190 |
+ |
|
| 191 |
+ @checker.options['rules'].first['value'] = ["hello world", "hello universe"] |
|
| 192 |
+ lambda {
|
|
| 193 |
+ @checker.receive([@event]) |
|
| 194 |
+ }.should change { Event.count }.by(1)
|
|
| 195 |
+ end |
|
| 196 |
+ |
|
| 127 | 197 |
it "handles negated comparisons" do |
| 128 | 198 |
@event.payload['foo']['bar']['baz'] = "hello world" |
| 129 | 199 |
@checker.options['rules'].first['type'] = "field!=value" |
@@ -140,6 +210,22 @@ describe Agents::TriggerAgent do |
||
| 140 | 210 |
}.should change { Event.count }.by(1)
|
| 141 | 211 |
end |
| 142 | 212 |
|
| 213 |
+ it "handles array of negated comparisons" do |
|
| 214 |
+ @event.payload['foo']['bar']['baz'] = "hello world" |
|
| 215 |
+ @checker.options['rules'].first['type'] = "field!=value" |
|
| 216 |
+ @checker.options['rules'].first['value'] = ["hello world", "hello world"] |
|
| 217 |
+ |
|
| 218 |
+ lambda {
|
|
| 219 |
+ @checker.receive([@event]) |
|
| 220 |
+ }.should_not change { Event.count }
|
|
| 221 |
+ |
|
| 222 |
+ @checker.options['rules'].first['value'] = ["hello there", "hello world"] |
|
| 223 |
+ |
|
| 224 |
+ lambda {
|
|
| 225 |
+ @checker.receive([@event]) |
|
| 226 |
+ }.should change { Event.count }.by(1)
|
|
| 227 |
+ end |
|
| 228 |
+ |
|
| 143 | 229 |
it "does fine without dots in the path" do |
| 144 | 230 |
@event.payload = { 'hello' => "world" }
|
| 145 | 231 |
@checker.options['rules'].first['type'] = "field==value" |